package com.aboo.pdfStamp;


import com.itextpdf.text.BadElementException;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import org.apache.commons.lang3.StringUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author louan
 * @description pdf骑缝章签名工具类
 */
//@Slf4j
public class PdfStampSigner {

    /**
     * @param src
     * @param dest
     * @param imagePath
     * @param stampWidth
     * @param stampHeight
     * @description 给pdf文件做骑缝章
     * @author louan
     */
    public static void signaturePdf(String src, String dest, String imagePath, int stampWidth, int stampHeight) {
        if (StringUtils.isAnyBlank(src, dest, imagePath) || stampWidth <= 0 || stampHeight <= 0) {
            return;
        }

        try {
            // Load the PDF document
            PdfReader pdfReader = new PdfReader(src);
            int numberOfPages = pdfReader.getNumberOfPages();

            // Create a PdfStamper to modify the PDF
            PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileOutputStream(dest));

            // 计算需要几个骑缝章，每个骑缝章负责多少页
            List<Integer> segmentArray = getSegmentArray(numberOfPages, 20);
            for (int i = 0; i < segmentArray.size(); i++) {
                // 从第startPage页到第endPage页，均分一个骑缝章
                int startPage = 1;
                int endPage = 0;
                int segment = segmentArray.get(i);
                for (int j = 0; j < i; j++) {
                    startPage += segmentArray.get(j);
                }
                if (i == segmentArray.size() - 1) {
                    endPage = startPage + segment - 1;
                } else {
                    endPage = startPage + segment;
                }
                System.out.println("startPage: " + startPage + ", endPage: " + endPage);

                // 计算每个骑缝章实际负责的页数，因为骑缝章有重合，所以需要做调整
                int splitNum = ((segmentArray.size() > 1 && i < segmentArray.size() - 1) ? segment + 1 : segment);
                // 盖一个骑缝章
                signatureOneStamp(i, imagePath, stampWidth, stampHeight, pdfReader, pdfStamper, splitNum, startPage);
            }

            // Close the PdfStamper
            pdfStamper.close();
            pdfReader.close();
        } catch (IOException | DocumentException e) {
//            log.error("为PDF文件添加骑缝章时出错，文件：{}", src, e);
            System.out.println(e);
        }
    }

    /**
     * @description 盖一个骑缝章
     * @author louan
     * @param index 用于控制骑缝章的位置，防止2个章重叠
     * @param imagePath 电子章路径
     * @param stampWidth 电子章总宽度
     * @param stampHeight 电子章总高度
     * @param pdfReader
     * @param pdfStamper
     * @param numberOfPages 当成骑缝章负责的总页数
     * @param startPage 当成骑缝章负责的起始页
     */
    private static void signatureOneStamp(int index, String imagePath, int stampWidth, int stampHeight, PdfReader pdfReader, PdfStamper pdfStamper,
            int numberOfPages, int startPage) throws IOException, DocumentException {
        System.out.println("numberOfPages: " + numberOfPages + ", startPage: " + startPage);
        // 获取骑缝章图片
        List<Image> slicesList = splitImage(imagePath, numberOfPages);
        int imageWidth = stampWidth / slicesList.size();
        int imageHeight = stampHeight;

        float offsetY = (index % 2 == 0) ? -50 : 50;
        // Iterate through each page and add the signature image
        for (int i = 1; i <= numberOfPages; i++) {
            Rectangle pageRect = pdfReader.getPageSize(startPage + i -1);
            Image signatureImage = slicesList.get(i - 1);
            signatureImage.scaleAbsolute(imageWidth, imageHeight);

            float x = pageRect.getLeft() + pageRect.getWidth() - imageWidth;
            float y = pageRect.getHeight() / 2 + offsetY;
            signatureImage.setAbsolutePosition(x, y);
            pdfStamper.getOverContent(startPage + i -1).addImage(signatureImage);
        }
    }

    /**
     * 切分图片
     *
     * @param imagePath 图片路径
     * @param num       切分数量
     * @return 切分后的图片列表
     * @throws IOException
     * @throws BadElementException
     */
    private static List<Image> splitImage(String imagePath, int num) throws IOException, BadElementException {
        BufferedImage originImage = ImageIO.read(new File(imagePath));
        int imgWidth = originImage.getWidth();
        int imgHeight = originImage.getHeight();
        int oneImageWidth = (int) Math.ceil((double) imgWidth / num);
        List<Image> slicesList = new ArrayList<>();
        BufferedImage images[] = new BufferedImage[num];
        int count = 0;
        // 切分图片
        for (int j = 0; j < num; j++) {
            images[count] = new BufferedImage(oneImageWidth, imgHeight, originImage.getType());
            // 最后一张图片的宽度可能不足oneImageWidth，需要调整
            int adjustWidthStart = (j == num - 1) ? imgWidth - oneImageWidth : oneImageWidth * j;
            images[count++].createGraphics().drawImage(originImage, 0, 0, oneImageWidth, imgHeight,
                    adjustWidthStart, 0, oneImageWidth * j + oneImageWidth, imgHeight, null);
        }
        for (int j = 0; j < num; j++) {
            Image image = Image.getInstance(images[j], null);
            slicesList.add(image);
        }
        return slicesList;
    }

    /**
     * @description 计算每份的数量，每份需要一个骑缝章
     * @author louan
     * @param pageNum
     * @param block
     * @return java.util.List<java.lang.Integer>
     */
    public static List<Integer> getSegmentArray(int pageNum, int block) {
        List<Integer> segmentArray = new ArrayList<>();
        int segmentNum = getSegmentNum(pageNum, block);

        int everyPageNum = pageNum / segmentNum;
        for (int i = 0; i < segmentNum - 1; i++) {
            segmentArray.add(everyPageNum);
        }
        segmentArray.add(pageNum - everyPageNum * (segmentNum - 1));
        return segmentArray;
    }

    /**
     * 获取分段数，即共需要多少骑缝章
     *
     * @param pageNum
     * @param block
     * @return
     */
    private static int getSegmentNum(int pageNum, int block) {
        if (pageNum <= block) {
            return 1;
        }
        int segment;
        int half = block / 2;
        for (segment = block - 1; segment >= half; segment--) {
            int leftNum = pageNum % segment;
            if (segment + leftNum <= block) {
                break;
            }
        }
        return pageNum / segment;
    }
}
